#include "Thread.hpp"
#include <unistd.h>
#include <stdio.h>
#include <vector>
#include "LockGuard.hpp"

void Print(int num) // 线程执行的方法
{
    while (num)
    {
        std::cout << "hello" << num-- << std::endl;
        sleep(1);
    }
}
std::string GetName() // 设置线程名
{
    static int number = 1;
    char name[64];
    snprintf(name, sizeof(name), "Threaad -%d", number++);
    return name;
}

int ticket = 10000;
// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//定义锁，定义并初始化了。
// //1.加锁尽量给少的代码块加锁
// //2.一般加锁，都是给临界区加锁
// void GetTicket(std::string name)
// {
//     while (true)
//     {
//        //非临界区
//        {
//         LockGuard lockguard(&mutex);
//         //根据互斥定义：任何时刻，只允许一个线程申请锁成功，多个线程申请失败，就必须等待。
//         //pthread_mutex_lock(&mutex);
//         if (ticket > 0)//一个线程在临界区访问临界资源时候，是可以发生切换，原因是被切换时，我把锁拿走了，其他线程根本进不去，必须等待解锁。
//         {
//             usleep(1000); // 抢票时间
//             printf("%s get a ticket:%d\n", name.c_str(), ticket);
//             ticket--;
//           //  pthread_mutex_unlock(&mutex);
//         }
//         else
//         {
//             //pthread_mutex_unlock(&mutex);
//             break;
//         }
//        }

//         // 实际情况，还有后续动作
//     }
// }

// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//定义锁，定义并初始化了。
// 1.加锁尽量给少的代码块加锁
// 2.一般加锁，都是给临界区加锁
// 3.可能有的线程一直占不到资源,这种叫做线程饥饿问题
//
class ThreadData
{
public:
    ThreadData(const std::string &name, pthread_mutex_t *putex)
        : _threadname(name), _pmutex(putex)
    {
    }
    std::string _threadname;
    pthread_mutex_t *_pmutex;
};

void GetTicket(ThreadData *td)
{
    while (true)
    {

        LockGuard lockguard(td->_pmutex);
        // 根据互斥定义：任何时刻，只允许一个线程申请锁成功，多个线程申请失败，就必须等待。
        // pthread_mutex_lock(mutex);
        if (ticket > 0) // 一个线程在临界区访问临界资源时候，是可以发生切换，原因是被切换时，我把锁拿走了，其他线程根本进不去，必须等待解锁。
        {
            usleep(1000); // 抢票时间
            printf("%s get a ticket:%d\n", td->_threadname.c_str(), ticket);
            ticket--;
            // pthread_mutex_unlock(mutex);
        }
        else
        {
            // pthread_mutex_unlock(mutex);
            break;
        }

        // 实际情况，还有后续动作
    }
}

int main()
{
    pthread_mutex_t mutex;
    // pthread_mutex_init(&mutex,nullptr);
    std::string name1 = GetName();
    ThreadData *td1 = new ThreadData(name1, &mutex);
    Thread<ThreadData *> t1(GetTicket, name1, td1);

    std::string name2 = GetName();
    ThreadData *td2 = new ThreadData(name2, &mutex);

    Thread<ThreadData *> t2(GetTicket, name2, td2);

    std::string name3 = GetName();
    ThreadData *td3 = new ThreadData(name3, &mutex);

    Thread<ThreadData *> t3(GetTicket, name3, td3);

    std::string name4 = GetName();
    ThreadData *td4 = new ThreadData(name4, &mutex);

    Thread<ThreadData *> t4(GetTicket, name4, td4);

    t1.Start();
    t1.Start();
    t2.Start();
    t3.Start();
    t4.Start();

    t1.join();
    t2.join();
    t3.join();
    t4.join();

    // std::string name1 = GetName();
    // Thread<std::string> t1(GetTicket, name1, name1);

    // std::string name2 = GetName();
    // Thread<std::string> t2(GetTicket, name2, name2);

    // std::string name3 = GetName();
    // Thread<std::string> t3(GetTicket, name3, name3);

    // std::string name4 = GetName();
    // Thread<std::string> t4(GetTicket, name4, name4);
    // t1.Start();
    // t1.Start();
    // t2.Start();
    // t3.Start();
    // t4.Start();

    // t1.join();
    // t2.join();
    // t3.join();
    // t4.join();
    // pthread_mutex_destroy(&mutex);
    // Thread<int> t(Print,GetName(),10);
    // t.Start();
    // t.join();

    // const int num = 5;
    // std::vector<Thread> threads;

    // for (int i = 0; i < num; i++)
    // {
    //     threads.push_back(Thread(Print, GetName()));
    // }

    // for (auto &t : threads)
    // {
    //     std::cout << "is running " << t.isrunning() << std::endl;
    // }
    // for (auto &t : threads)
    // {
    //     t.Start();
    // }
    // for (auto &thread : threads)
    // {
    //     std::cout << thread.name() << " is running" << thread.isrunning() << std::endl;
    // }

    // for (auto &t : threads)
    // {
    //     t.join();
    // }

    // Thread t(Print, GetName());
    // std::cout << "is running" << t.isrunning() << std::endl;
    // t.Start();

    // t.join();
    delete td1;
    delete td2;
    delete td3;
    delete td4;

    return 0;
}